<?php

use app\common\model\TagCount;
use GatewayWorker\Lib\Gateway;
use Workerman\Lib\Timer;


/**
 * 主逻辑
 * 主要是处理 onConnect onMessage onClose 三个方法
 * onConnect 和 onClose 如果不需要可以不用实现并删除
 */
//error_reporting(E_ERROR);

class Events
{
    /**
     * @var Redis
     */
    static $redis;
    static $worker;

    public static function onWorkerStart($worker)
    {
        self::$worker = $worker;
        self::$redis  = get_redis();
    }


    /**
     * 当客户端连接时触发
     * 如果业务不需此回调可以删除onConnect
     *
     * @param int $client_id 连接id
     */
    public static function onConnect($client_id)
    {

        // 连接到来后，定时30秒关闭这个链接，需要30秒内发认证并删除定时器阻止关闭连接的执行
        $session                  = Gateway::getSession($client_id);
        $session['auth_timer_id'] = Timer::add(30, function ($client_id) {
            self::closeOnNoLogin($client_id, 'auto close');
        }, array($client_id), false);
        Gateway::updateSession($client_id, $session);
        // 向当前client_id发送数据
        GateWay::sendToClient($client_id, self::success("connected"));
        echo '连接:[ ' .$client_id . PHP_EOL;
    }

    /**
     * 当客户端发来消息时触发
     * @param int $client_id 连接id
     * @param mixed $message 具体消息
     */
    public static function onMessage($client_id, $message)
    {
        // echo_log(  ' 回执 ' . $message);
        echo '消息:[ ' . $client_id.' '.$message . PHP_EOL;
        if (stripos($message, '@H') === 0) {
            $cmd_arr = explode(':', $message);
            if (!empty($cmd_arr[2])) {
                $session = Gateway::getSession($client_id) ?: array();
                $value   = $cmd_arr[2];
                switch ($cmd_arr[1]) {
                    case 'uid':
                        if ($value && (!isset($session['uid']) || !$session['uid'])) {
                            $tag = $cmd_arr[3];
                            Timer::del($session['auth_timer_id']);
                            $session['uid'] = $value;
                            $session['tag'] = $tag;
                            Gateway::joinGroup($client_id, $tag);
                            Gateway::updateSession($client_id, $session);
                            self::sendClientCount($client_id, $value, $tag);
                            Gateway::sendToClient($client_id, self::success(self::getRandCount($tag), '上线', 2));
                            echo '上线:[ ' . $session['uid'] . PHP_EOL;
                        }
                        Gateway::sendToClient($client_id, self::success('', 'runing'));
                        break;
                    case 'tag':
                        $tag   = $value;
                        $uid   = $session['uid'];
                        $redis = get_redis();
                        $info  = $redis->get("$uid|info");
                        if ($info) {
                            $info    = json_decode($info, true);
                            $ip      = $info['ip'];
                            $address = get_address($ip);
                            $ip      = ip2long($ip);
                            $key     = "$ip|$tag";
                            //计数累计
                            $count = $redis->incr($key);
                            if (!$redis->exists("$uid|uid|$tag")) {
                                $redis->set("$uid|uid|$tag", "$count");
                            } else {
                                 $redis->incr("$uid|uid|$tag");
                            }

                            if ($address) {
                                //位置计数累计
                                $province     = $address['province'];
                                $city         = $address['city'];
                                $province_key = "provincecount|$tag|$province";
                                $redis->incr($province_key);
                                $city_key = "citycount|$tag|$province|$city";
                                $redis->incr($city_key);
                            }

                            if (isset($session['refresh_timer_id'])) {
                                Timer::del($session['refresh_timer_id']);
                            }
                            //延迟刷新同步至数据库
                            $session['refresh_timer_id'] = Timer::add(5, function ($client_id) use ($ip, $tag, $count) {
                                $tagCount = TagCount::get(['ip' => $ip]);
                                if (!$tagCount) {
                                    TagCount::create([
                                        'ip'    => $ip,
                                        'tag'   => $tag,
                                        'count' => $count,
                                    ]);
                                } else {
                                    $tagCount['count'] = $count;
                                    $tagCount->save();
                                }
                                self::sendRankCount($tag);
                            }, array($client_id), false);
                            Gateway::updateSession($client_id, $session);
                            self::sendClientCount($client_id, $uid, $tag);
                        }
                        break;

                }
            } else {
                echo 'message ' . $message . PHP_EOL;
                self::closeOnNoLogin($client_id, 'cmd error');
            }
            return;
        } else {
            Gateway::sendToClient($client_id, $message);
        }
    }

    protected static function sendTotalCount($client_id, $uid, $tag)
    {
        $redis = get_redis();
        $info  = $redis->get("$uid|info");
        if ($info) {
            $info = json_decode($info, true);
            $ip   = $info['ip'];
            $ip   = ip2long($ip);
            $key  = "$ip|$tag";
            //计数累计
            $count = $redis->get($key)?:0;
            Gateway::sendToClient($client_id, self::success([
                'count' => $count,
                'type'  => 'count'
            ], $tag));
        }
    }
    protected static function sendClientCount($client_id, $uid, $tag)
    {
        $redis = get_redis();
        $info  = $redis->get("$uid|info");
        if ($info) {
            $info = json_decode($info, true);
            $ip   = $info['ip'];
            $ip   = ip2long($ip);
            $key  = "$ip|$tag";
            //计数累计
            $count = $redis->get($key)?:0;
            Gateway::sendToClient($client_id, self::success([
                'count' => $count,
                'type'  => 'count'
            ], $tag));
        }
    }

    protected static function getRandCount($tag,$limit=10)
    {
        $redis     = get_redis();
        $provinces = $redis->keys("provincecount|$tag|*");
        $ranks     = [];
        $total=0;
        foreach ($provinces as $province_key) {
            $province = str_replace("provincecount|$tag|", '', $province_key);
            $count=intval($redis->get($province_key));
            $total=$total+$count;
            $ranks[]  = [
                'province' => $province,
                'count'    => $count
            ];
        }
        array_multisort(array_column($ranks, 'count'), SORT_DESC, $ranks);
        $ranks = array_slice($ranks, 0, $limit);
        return ['total'=>$total,'ranks'=>$ranks,'type'=>'ranks','online'=>Gateway::getClientCountByGroup($tag)];
    }

    protected static function sendRankCount($tag)
    {
        $ranks = self::getRandCount($tag);

        Gateway::sendToGroup($tag, self::success($ranks, $tag));
    }

    /**
     * 当用户断开连接时触发
     * @param int $client_id 连接id
     */
    public static function onClose($client_id)
    {


        $session = $_SESSION;//Gateway::getSession($client_id) ?: array();
        echo 'onClose $client_id ' . $client_id . PHP_EOL;
        if (isset($session['uid'])) {
            $uid = $session['uid'];
            echo '下线:[ ' . $session['uid'] . PHP_EOL;
            Gateway::leaveGroup($client_id,$session['tag']);
            Timer::del($session['auth_timer_id']);
        }
        /**解除socket客户端到uid的绑定*/

    }

    public static function closeOnNoLogin($client_id, $info = '')
    {
        Gateway::closeClient($client_id, self::error('未登录.', $info, 403));
    }

    /**
     * 请求成功返回
     * @param null $info
     * @param string $msg
     * @param int $status
     * @return string
     */
    public static function success($info = null, $msg = null, $status = 1)
    {
        // 返回JSON数据格式到客户端 包含状态信息

        $result = array('code' => $status);
        if ($msg) {
            $result['msg'] = $msg;
        }
        if ($info) {
            $result['data'] = $info;
        }
        return json_encode($result);
    }

    /**
     * 请求失败返回
     * @param null $info
     * @param string $msg
     * @param int $status
     * @return string
     */
    public static function error($msg = '请求失败', $info = null, $status = 0)
    {
        // 返回JSON数据格式到客户端 包含状态信息
        $result = array('code' => $status);
        if ($msg) {
            $result['msg'] = $msg;
        }
        if ($info) {
            $result['data'] = $info;
        }
        return json_encode($result);
    }


}